 /*
 * File:   AHP.cpp
 * Author: darkflako
 * 
 * Created on December 16, 2011, 12:01 PM
 */

#include "AHP.h"
#include <iostream>
#include <iterator>
using namespace std;

AHP::AHP() {
}

AHP::AHP(const AHP& orig) {
}

AHP::~AHP() {
}

void AHP::addAlternativa(string c){
    this->alternativas.push_front(c);
}

void AHP::delAlternativa(string c){
    this->alternativas.remove(c);
}

void AHP::addCriterio(string c){
    this->criterios.push_back(c);
}

void AHP::delCriterio(string c){
    this->criterios.remove(c);
}

int AHP::countAlternativas(){
    return alternativas.size();
}

int AHP::countCriterios(){
    return criterios.size();
}

list<string> AHP::getAlternativas(){
    return this->alternativas;
}

list<string> AHP::getCriterios(){
    return this->criterios;
}

void AHP::setComparacionAlternativas(string criterio, string alternativa1, string alternativa2, float v){
    string key = criterio + string(";") + alternativa1 + string(";") + alternativa2;
    string key_inv = criterio + string(";") + alternativa2 + string(";") + alternativa1;
    if (v != 0){
        this->comparaciones[key]=v;
        this->comparaciones[key_inv]=1/v;
    } else {
        this->comparaciones[key]=0; //por definición el valor mínimo que puede asignarse a una comparacion es 1
        this->comparaciones[key_inv]=0;
    }
}

float AHP::getComparacionAlternativas(string criterio, string alternativa1, string alternativa2){
    if ( alternativa1 != alternativa2){
        string key = criterio + string(";") + alternativa1 + string(";") + alternativa2;
        if(this->comparaciones.find(key)!=this->comparaciones.end()){
            return this->comparaciones[key];
        } else {
            return 1;
        }
    } else {
        return 1;
    }
}

void AHP::setComparacionCriterios(string criterio1, string criterio2, float v){
    string key = criterio1 + string(";") + criterio2;
    string key_inv = criterio2 + string(";") + criterio1;
    if (v != 0){
        this->comparacionesCriterios[key]=v;
        this->comparacionesCriterios[key_inv]=1/v;
    } else {
        this->comparacionesCriterios[key]=0;
        this->comparacionesCriterios[key_inv]=0;
    }
}

float AHP::getComparacionCriterios(string criterio1, string criterio2){
    if (criterio1 != criterio2){
        string key = criterio1 + string(";") + criterio2;
        if(this->comparacionesCriterios.find(key)!=this->comparacionesCriterios.end()){
            return this->comparacionesCriterios[key];
        } else {
            return 1;
        }
    } else {
        return 1;
    }
}

void AHP::printData(){
    cout << "Comparaciones entre alternativas:" << endl;

    map<string,float>::iterator it = this->comparaciones.begin();
    while(it!=this->comparaciones.end()){
        cout << "Clave: " << it->first << " Valor: " << it->second << endl;
        it++;
    }
}

map<string,float> AHP::calcular(){
    int size=this->alternativas.size();
    int sizec=this->criterios.size();
    float matriz[sizec][size][size]; //matrices de comparacion de pares de alternativas normalizadas
    int c=0;


    //Se calculan las matrices de comparacion de pares de alternativas normalizadas
    for(list<string>::iterator criterio=this->criterios.begin();criterio!=this->criterios.end();criterio++){  //por cada criterio
        int i=0;
        
        for(list<string>::iterator alternativa1 = this->alternativas.begin();alternativa1!=this->alternativas.end();alternativa1++){
            float suma=0;
            for(list<string>::iterator alternativa2 = this->alternativas.begin();alternativa2!=this->alternativas.end();alternativa2++){
                suma+=this->getComparacionAlternativas(*criterio,*alternativa2,*alternativa1);
            }
            int j=0;
            for(list<string>::iterator alternativa2 = this->alternativas.begin();alternativa2!=this->alternativas.end();alternativa2++){
                matriz[c][i][j]=this->getComparacionAlternativas(*criterio,*alternativa2,*alternativa1)/suma;
                j++;
            }
            i++;
        }

        c++;
    }

    float vector[sizec][size];  //matriz prioridades

    for (int c=0;c<sizec;c++){ //por cada criterio
        for(int i=0;i<size;i++){
            float suma=0;
            for(int j=0;j<size;j++){
                suma+=matriz[c][j][i];
            }

            vector[c][i]=suma/size; //TODO Son promedios!!! falta dividir por la cantidad de alternativas
        }
    }

    int c1=0;
    
    float matrizCriterios[sizec][sizec];
    for(list<string>::iterator criterio1=this->criterios.begin();criterio1!=this->criterios.end();criterio1++){
        float suma=0;
        for(list<string>::iterator criterio2=this->criterios.begin();criterio2!=this->criterios.end();criterio2++){
            suma+=this->getComparacionCriterios(*criterio1,*criterio2);
        }

        int c2=0;
        for(list<string>::iterator criterio2=this->criterios.begin();criterio2!=this->criterios.end();criterio2++){
            matrizCriterios[c1][c2]=this->getComparacionCriterios(*criterio1,*criterio2)/suma;
            c2++;
        }
        c1++;
    }

    float vectorCriterios[sizec];

    for(int i=0;i<sizec;i++){
        float suma=0;
        for(int j=0;j<sizec;j++){
            suma+=matrizCriterios[j][i];
        }

        vectorCriterios[i]=suma/size;  //TODO Son promedios!!! falta dividir por la cantidad de criterios
    }

    map<string,float> valores;

    // se multiplica la matriz de prioridades por el vector prioridad de los criterios
    int a=0;
    for(list<string>::iterator it = alternativas.begin(); it!= alternativas.end(); it++){
        float suma=0;
        for(int c=0;c<sizec;c++){
            suma+=(vector[c][a]) * (vectorCriterios[c]);
        }

        valores[*it]=suma;

        a++;
    }



    float suma=0;

    for(map<string,float>::iterator it=valores.begin();it!=valores.end();it++){
        suma+=it->second;
    }

    for(map<string,float>::iterator it=valores.begin();it!=valores.end();it++){
        it->second=it->second/suma;
    }



    return valores;
}

void AHP::clear(){
    this->criterios.clear();
    this->comparaciones.clear();
    this->alternativas.clear();
    this->comparacionesCriterios.clear();
}
